home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
The World of Computer Software.iso
/
pcmagwin.zip
/
SYSMON.C
< prev
next >
Wrap
Text File
|
1992-12-16
|
29KB
|
828 lines
// SysMon - Simple System Monitor for Windows NT
// Uses Performance Data Block in System Registry
// Tested with Oct 92 (beta) Release of Windows NT
// Copyright (C) 1992 Ray Duncan
// PC Magazine * Ziff Davis Publishing
#define dim(x) (sizeof(x) / sizeof(x[0])) // returns no. of elements
#define MAXLINES 4096 // max lines to display
#define MALLOCINCR 4096
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winperf.h>
#include "sysmon.h"
HANDLE hInst; // module instance handle
HWND hFrame; // handle for frame window
HFONT hFont; // handle for nonprop. font
int CharX, CharY; // character dimensions
int LinesPerPage; // lines per page
int CurLine = 0; // first line, current page
int TotLines = 0; // total lines to display
int TopLine = 0; // first line of last page
int DisplayType = IDM_OBJECT; // default display type
char *LinePtr[MAXLINES]; // holds pointers to lines
char szFrameClass[] = "SysMon"; // classname for frame window
char szAppName[] = "System Monitor"; // long application name
char szMenuName[] = "SysMonMenu"; // name of menu resource
char szIcon[] = "SysMonIcon"; // name of icon resource
char szIni[] = "sysmon.ini"; // name of private INI file
DWORD dwPerfDataLen = 0; // size of performance data
PPERFDATA pPerfData; // addr of perf data block
PPERFGROUP pFirstGroup; // addr of first object group
INT iTotGroups; // total object groups
PSTR pTitles; // addr of object title database
//
// Table of window messages supported by FrameWndProc()
// and the functions which correspond to each message.
//
struct decodeMsg frameMsgs[] = {
WM_PAINT, DoPaint,
WM_SIZE, DoSize,
WM_COMMAND, DoCommand,
WM_SETFOCUS, DoSetFocus,
WM_CLOSE, DoClose,
WM_DESTROY, DoDestroy,
WM_VSCROLL, DoVScroll, } ;
//
// Table of menubar item IDs and their corresponding functions.
//
struct decodeMsg menuitems[] = {
IDM_EXIT, DoMenuExit,
IDM_ABOUT, DoMenuAbout,
IDM_OBJECT, DoDisplayType,
IDM_PROCESS, DoDisplayType,
IDM_REFRESH, DoRefresh, } ;
//
// WinMain -- entry point for this application from Windows.
//
int APIENTRY WinMain(HANDLE hInstance,
HANDLE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
MSG msg; // scratch message storage
hInst = hInstance; // save this instance handle
if(!InitApp(hInstance, nCmdShow)) // initialize everything
{
MessageBox(hFrame, "Initialization failed!", szAppName,
MB_ICONSTOP | MB_OK);
return(FALSE);
}
while(GetMessage(&msg, NULL, 0, 0)) // while message != WM_QUIT
{
TranslateMessage(&msg); // translate virtual key codes
DispatchMessage(&msg); // dispatch message to window
}
TermApp(hInstance); // clean up everything
return(msg.wParam); // return code = WM_QUIT value
}
//
// InitApp --- application initialization code.
//
BOOL InitApp(HANDLE hInstance, int nCmdShow)
{
WNDCLASS wc; // window class info
HDC hdc; // handle for device context
TEXTMETRIC tm; // info about font
RECT rect; // window position & size
int i; // scratch variable
// set parameters for frame window class
wc.style = CS_HREDRAW|CS_VREDRAW; // class style
wc.lpfnWndProc = FrameWndProc; // class callback function
wc.cbClsExtra = 0; // extra per-class data
wc.cbWndExtra = 0; // extra per-window data
wc.hInstance = hInstance; // handle of class owner
wc.hIcon = LoadIcon(hInst, szIcon); // application icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // default cursor
wc.hbrBackground = GetStockObject(WHITE_BRUSH); // background color
wc.lpszMenuName = szMenuName; // name of menu resource
wc.lpszClassName = szFrameClass; // name of window class
// register frame window class, abort application if fails
if(!RegisterClass(&wc))
return(FALSE);
for(i = 0; i < MAXLINES; i++) // initialize all line
LinePtr[i] = NULL; // pointers
hFrame = CreateWindow( // create frame window
szFrameClass, // window class name
szAppName, // text for title bar
WS_OVERLAPPEDWINDOW | WS_VSCROLL, // window style
CW_USEDEFAULT, CW_USEDEFAULT, // default position
CW_USEDEFAULT, CW_USEDEFAULT, // default size
NULL, // no parent window
NULL, // use class default menu
hInstance, // window owner
NULL); // unused pointer
if(!hFrame) return(FALSE); // error, can't create window
hdc = GetDC(hFrame); // get device context
hFont = GetStockObject(SYSTEM_FIXED_FONT); // handle for nonprop. font
SelectObject(hdc, hFont); // realize the font and get
GetTextMetrics(hdc, &tm); // the character dimensions
CharX = tm.tmAveCharWidth;
CharY = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hFrame, hdc); // release device context
GetWindowRect(hFrame, &rect); // current window pos & size
// read profile for frame window from previous invocation, if any
rect.left = GetPrivateProfileInt("Frame", "xul", rect.left, szIni);
rect.top = GetPrivateProfileInt("Frame", "yul", rect.top, szIni);
rect.right = GetPrivateProfileInt("Frame", "xlr", rect.right, szIni);
rect.bottom = GetPrivateProfileInt("Frame", "ylr", rect.bottom, szIni);
MoveWindow(hFrame, rect.left, rect.top, // force window size & position
rect.right-rect.left, rect.bottom-rect.top, TRUE);
// get display type from previous invocation, default to module list
DisplayType = GetPrivateProfileInt("Frame", "type", IDM_OBJECT, szIni);
// allocate initial buffer to receive performance data
// this buffer will be grown as necessary by GetPerfData
dwPerfDataLen = MALLOCINCR;
pPerfData = (PPERFDATA) malloc(dwPerfDataLen);
if(pPerfData == NULL)
return(FALSE);
// fetch names of object types from system registry
if(!GetObjectTitles())
return(FALSE);
// fetch system performance data from system registry
if(!GetPerfData())
return(FALSE);
// set up our 10 sec. (10,000 msec) timer callback
if (!SetTimer(hFrame, 1, 10000, (WNDPROC) TimerProc))
return(FALSE);
ShowWindow(hFrame, nCmdShow); // make frame window visible
// simulate a Display menu command to turn on the menu checkmark
// for the current display type, and force update of the window
PostMessage(hFrame, WM_COMMAND, DisplayType, 0);
return(TRUE); // return success flag
}
//
// TermApp -- centralized clean-up code for application.
// Does nothing in this particular implementation.
//
BOOL TermApp(HANDLE hinstance)
{
return(TRUE); // return success flag
}
//
// FrameWndProc --- callback function for application frame window.
// Searches frameMsgs[] for message match, runs corresponding function.
//
LONG CALLBACK FrameWndProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
int i; // scratch variable
for(i = 0; i < dim(frameMsgs); i++) // decode window message and
{ // run corresponding function
if(wMsg == frameMsgs[i].Code)
return((*frameMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam));
}
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
//
// DoCommand -- process WM_COMMAND message for frame window by
// decoding the menubar item with the menuitems[] array, then
// running the corresponding function to process the command.
//
LONG DoCommand(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
int i; // scratch variable
for(i = 0; i < dim(menuitems); i++) // decode menu command and
{ // run corresponding function
if(wParam == menuitems[i].Code)
return((*menuitems[i].Fxn)(hWnd, wMsg, wParam, lParam));
}
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
//
// DoDestroy -- process WM_DESTROY message for frame window.
//
LONG DoDestroy(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
PostQuitMessage(0); // force WM_QUIT message to
return(0); // terminate the event loop
}
//
// DoClose -- process WM_CLOSE message for frame window.
//
LONG DoClose(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
UpdateProfile(); // save window size & position
DestroyWindow(hWnd); // then close down app
return(FALSE);
}
//
// DoVScroll -- process WM_VSCROLL message for frame window.
//
LONG DoVScroll(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
RECT rect;
switch(LOWORD(wParam)) // LOWORD vital for Win32
{
case SB_TOP: // go to top of output if
if(CurLine) // we aren't there already
{
SetCurLine(0);
Repaint();
}
break;
case SB_BOTTOM: // go to bottom of output if
if(CurLine < TopLine) // we aren't there already
{
SetCurLine(TopLine);
Repaint();
}
break;
case SB_LINEUP: // scroll up by one line if
if(CurLine) // we aren't already at top
{
SetCurLine(CurLine - 1);
ScrollWindow(hWnd, 0, CharY, NULL, NULL);
UpdateWindow(hWnd);
}
break;
case SB_LINEDOWN: // scroll down by one line if
if(CurLine < TopLine) // we aren't already at bottom
{
SetCurLine(CurLine + 1);
ScrollWindow(hWnd, 0, -CharY, NULL, NULL);
GetClientRect(hWnd, &rect);
rect.top = max(0, (LinesPerPage-1) * CharY);
InvalidateRect(hWnd, &rect, TRUE);
UpdateWindow(hWnd);
}
break;
case SB_PAGEUP: // scroll up by one page
SetCurLine(CurLine - LinesPerPage);
Repaint();
break;
case SB_PAGEDOWN: // scroll down by one page
SetCurLine(CurLine + LinesPerPage);
Repaint();
break;
case SB_THUMBPOSITION: // scroll display according
SetCurLine(THUMBPOS); // to new thumb position
Repaint();
break;
}
return(FALSE);
}
//
// DoPaint -- process WM_PAINT message for frame window.
//
LONG DoPaint(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
HDC hdc;
PAINTSTRUCT ps;
int i;
hdc = BeginPaint(hWnd, &ps); // get device context
SelectObject(hdc, hFont); // select non-prop. font
for(i = 0; i < LinesPerPage; i++) // paint lines of text
PaintLine(hdc, i); // in the window
EndPaint(hWnd, &ps); // release device context
return(FALSE);
}
//
// DoSize -- process WM_SIZE message for frame window. Recalculate
// lines per page, if window has grown and at end of file may need to
// change first line in window and refresh it.
//
LONG DoSize(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
LinesPerPage = HIWORD(lParam) / CharY; // window height / char height
ConfigWindow(); // calc display parameters
if(CurLine > TopLine) // make sure window refilled
SetCurLine(TopLine); // if window got bigger
return(FALSE);
}
//
// DoSetFocus -- process WM_SETFOCUS message for frame window.
// Refresh display in case something has changed since last in foreground.
// This also gets called when app is launched after window is created.
//
LONG DoSetFocus(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0);
return(FALSE);
}
//
// DoMenuExit -- process File-Exit command from menu bar.
//
LONG DoMenuExit(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
SendMessage (hWnd, WM_CLOSE, 0, 0L); // send window close message
return(FALSE); // to shut down the app
}
//
// DoDisplayType -- process items on Display popup to select
// the type of information to display, then force window update
//
LONG DoDisplayType(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
HMENU hMenu; // scratch menu handle
hMenu = GetMenu(hWnd); // update popup checkmark
CheckMenuItem(hMenu, DisplayType, MF_UNCHECKED);
DisplayType = wParam;
CheckMenuItem(hMenu, DisplayType, MF_CHECKED);
SendMessage(hWnd, WM_COMMAND, IDM_REFRESH, 0); // update window
return(FALSE);
}
//
// DoRefresh -- rebuild the information for display according to
// the currently selected display type, then refresh the window.
//
LONG DoRefresh(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
EmptyLines(); // discard old output
// fetch fresh copy of system performance data block
GetPerfData();
// call the appropriate list walking routine
// according to the currently selected display type
switch(DisplayType)
{
case IDM_OBJECT:
WalkObjects();
SetWindowCaption("Objects");
break;
case IDM_PROCESS:
WalkProcesses();
SetWindowCaption("Processes");
break;
}
ConfigWindow(); // configure scroll bar etc.
Repaint(); // refresh the window
return(FALSE);
}
//
// DoMenuAbout -- process File-About command from menu bar.
//
LONG DoMenuAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
// allocate a thunk for the dialog callback, then display dialog
DialogBox(hInst, "AboutBox", hWnd, (WNDPROC) AboutDlgProc);
return(FALSE);
}
//
// AboutDlgProc -- callback routine for About... dialog. Basically
// ignores all messages except for the OK button, which dismisses dialog.
//
BOOL CALLBACK AboutDlgProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
if((msg == WM_COMMAND) && (wParam == IDOK))
EndDialog(hwnd, 0); // if OK button, destroy dialog
else return(FALSE); // otherwise ignore message
}
//
// WalkObjects -- Lists the object types found in the system
// registry and the number of counters and instances for each.
//
VOID WalkObjects(VOID)
{
char temp[256];
INT iCurGroup;
PPERFGROUP pCurGroup;
// format title for itemized data
AddLine("Group Description Counters Instances");
// begin at first object group
pCurGroup = pFirstGroup;
// walk through object groups, printing for each the position,
// object type name, number of counters, and number of instances
for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
{
wsprintf(temp, "%3d %-32s %5d %5d", iCurGroup,
pCurGroup->ObjectNameTitle,
pCurGroup->NumCounters, pCurGroup->NumInstances);
AddLine(temp);
// advance to next group of objects
pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup +
pCurGroup->TotalByteLength);
}
}
//
// WalkProcesses -- displays process instances and counters from the
// system performance registry.
//
VOID WalkProcesses(VOID)
{
char temp[256];
PPERFGROUP pCurGroup;
PPERFINSTANCE pCurInst;
PPERFCOUNTERS pCurCounters;
INT iCurInst;
INT iTotInst;
// find appropriate object group within the performance data
pCurGroup = FindGroup("Process");
// bail out now if there is nothing to display
if(pCurGroup == NULL)
{
AddLine("Process object group was not found!");
return;
}
// extract pointer to first instance and total number of
// instances from the header for the process object group
pCurInst = (PPERFINSTANCE) ((PBYTE) pCurGroup +
pCurGroup->DefinitionLength);
iTotInst = pCurGroup->NumInstances;
for(iCurInst = 0; iCurInst < iTotInst; iCurInst++)
{
// convert UNICODE process name to ASCIIZ and display it
wcstombs(temp, (LPWSTR) ((PBYTE) pCurInst + pCurInst->NameOffset),
pCurInst->NameLength/sizeof (WCHAR));
AddLine(temp);
// advance to next process instance
pCurCounters = (PPERFCOUNTERS) ((PBYTE) pCurInst +
pCurInst->ByteLength);
pCurInst = (PPERFINSTANCE) ((PBYTE) pCurCounters +
pCurCounters->ByteLength);
}
}
//
// SetCurLine - called to set CurLine to valid value, clamped to
// the range (0...TopLine), and redraw thumb on scroll bar.
//
VOID SetCurLine(int NewLine)
{
CurLine = min(max(NewLine, 0), TopLine);
SetScrollPos(hFrame, SB_VERT, CurLine, TRUE);
}
//
// ConfigWindow -- Configures various display parameters and scrollbar
// according to total lines of output, current window size, and the
// number of lines that will fit into the window.
//
VOID ConfigWindow(VOID)
{
// calc line number of first line of last page
TopLine = max(TotLines - LinesPerPage,0);
// update scroll bar range and thumb position
SetScrollRange(hFrame, SB_VERT, 0, TopLine, FALSE);
SetScrollPos(hFrame, SB_VERT, CurLine, TRUE);
}
//
// AddLine -- called with a pointer to an ASCIIZ string, allocates
// memory from the heap to hold the string, puts the pointer
// to the heap block into the next position in the LinePtr[] array,
// and updates the total line count.
//
VOID AddLine(char * p)
{
char * q; // scratch pointer
if(TotLines == MAXLINES) // bail out if line pointer
return; // array is already full
q = malloc(strlen(p)+1); // allocate memory for line
if(q == 0) // bail out out if no
return; // heap space available
strcpy(q, p); // copy string to heap
LinePtr[TotLines] = q; // put heap pointer into array
TotLines++; // count lines of output
}
//
// EmptyLines - releases all heap blocks in LinePtr[] array,
// then zeros out the line pointers and the total line count
//
VOID EmptyLines(VOID)
{
int i; // scratch variable
for(i = 0; i < MAXLINES; i++)
{
if(LinePtr[i]) // if this position in
{ // the LinePtr array is
free(LinePtr[i]); // nonzero, release the
LinePtr[i] = NULL; // heap block, then zero
} // out the LinePtr slot
}
CurLine = 0; // initialize various
TotLines = 0; // other global variables
TopLine = 0;
}
//
// PaintLine -- paint a single line of text in the window.
// The passed line number is relative to the window, NOT to the
// total array of formatted output available to be painted.
//
VOID PaintLine(HDC hdc, INT RelLine)
{
int Line = RelLine + CurLine;
if(LinePtr[Line])
TextOut(hdc, CharX, RelLine*CharY, LinePtr[Line], strlen(LinePtr[Line]));
}
//
// Repaint - force repaint of all formatted output in main window
//
VOID Repaint(VOID)
{
InvalidateRect(hFrame, NULL, TRUE); // force repaint entire window
}
//
// SetWindowCaption -- concatenate the application name with the
// display type, then update the frame window's title bar.
//
VOID SetWindowCaption(char * szDisplayType)
{
char szTemp[256]; // scratch buffer
strcpy(szTemp, szAppName); // get application name
strcat(szTemp, " - "); // add separator
strcat(szTemp, szDisplayType); // add information type
SetWindowText(hFrame, szTemp); // put result into title bar
}
//
// UpdateProfile() -- saves the current window size and position
// and display type in the application's private INI file.
//
VOID UpdateProfile(VOID)
{
RECT rect;
char temp[20];
if(IsIconic(hFrame) || IsZoomed(hFrame)) return;
GetWindowRect(hFrame, &rect);
wsprintf(temp,"%d", rect.left);
WritePrivateProfileString("Frame", "xul", temp, szIni);
wsprintf(temp,"%d", rect.top);
WritePrivateProfileString("Frame", "yul", temp, szIni);
wsprintf(temp,"%d", rect.right);
WritePrivateProfileString("Frame", "xlr", temp, szIni);
wsprintf(temp,"%d", rect.bottom);
WritePrivateProfileString("Frame", "ylr", temp, szIni);
wsprintf(temp,"%d", DisplayType);
WritePrivateProfileString("Frame", "type", temp, szIni);
}
//
// TimerProc() -- Callback for 10 second timer. Refresh display
// if window is not minimized and does not have the focus.
//
WORD CALLBACK TimerProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
if((!IsIconic(hFrame)) && (hFrame != GetFocus()))
SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0);
return(FALSE);
}
//
// GetPerfData() - obtain performance data block from the
// system registry. The size of the data cannot be known in advance
// so the buffer is expanded incrementally until it is big enough.
//
BOOL GetPerfData(VOID)
{
INT iCurGroup;
PPERFGROUP pCurGroup;
DWORD dwBufferSize = dwPerfDataLen;
while(ERROR_MORE_DATA ==
RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global",
NULL, NULL, (PSTR) pPerfData, &dwBufferSize))
{
dwPerfDataLen += MALLOCINCR;
dwBufferSize = dwPerfDataLen;
pPerfData = (PPERFDATA) realloc(pPerfData, dwPerfDataLen);
if(pPerfData == NULL)
{
MessageBox(hFrame, "GetPerfData malloc failed!", szAppName,
MB_ICONSTOP | MB_OK);
return(FALSE);
}
}
// point to first object group within the data block and
// save total number of object groups
pFirstGroup = (PPERFGROUP) ((PBYTE) pPerfData + pPerfData->HeaderLength);
iTotGroups = pPerfData->NumObjectTypes;
// point to the first group of objects
pCurGroup = pFirstGroup;
// look up titles for each object type and save pointer
// within the object group's header structure
for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
{
pCurGroup->ObjectNameTitle = (LPWSTR)
FindTitle(pCurGroup->ObjectNameTitleIndex);
// advance to next group of objects
pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup +
pCurGroup->TotalByteLength);
}
return(TRUE);
}
//
// GetObjectTitles() - retrieve titles for each of the object
// types from the system registry. The retrieved data, which is
// referred to as the title database, is in the form of a series of
// pairs of ASCIIZ strings. The first string of a pair is the object
// type index in decimal, the second string is the title. The entire
// set of strings is terminated by an extra null byte.
//
BOOL GetObjectTitles(VOID)
{
HKEY hKey;
char chClass[10];
DWORD dwType;
DWORD cSubKeys;
DWORD cbMaxSubkey;
DWORD cbMaxClass;
DWORD cValues;
DWORD cbMaxValueName;
DWORD cbMaxValueData;
DWORD cbSecurityDescriptor;
DWORD cbClassSize = 10 ; // sizeof(chClass);
FILETIME ftLastWriteTime;
// get handle for subkey holding object type indexes and titles
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\409",
0, KEY_QUERY_VALUE, &hKey))
{
MessageBox(hFrame, "RegOpenKeyEx failed!", szAppName,
MB_ICONSTOP | MB_OK);
return(FALSE);
}
// get maximum size of value data for values reached thru this subkey
if(ERROR_SUCCESS != RegQueryInfoKey(hKey, chClass, &cbClassSize, NULL,
&cSubKeys, &cbMaxSubkey, &cbMaxClass, &cValues, &cbMaxValueName,
&cbMaxValueData, &cbSecurityDescriptor, &ftLastWriteTime))
{
MessageBox(hFrame, "RegQueryInfoKey failed!", szAppName,
MB_ICONSTOP | MB_OK);
RegCloseKey(hKey);
return(FALSE);
}
// bump maximum data size value for safety
cbMaxValueData++;
// allocate memory to hold the incoming data
pTitles = malloc(cbMaxValueData * sizeof(TCHAR));
if(pTitles == NULL)
{
MessageBox(hFrame, "GetObjectTitles malloc failed!", szAppName,
MB_ICONSTOP | MB_OK);
RegCloseKey(hKey);
return(FALSE);
}
// now retrieve the index and title data
if(ERROR_SUCCESS != RegQueryValueEx(hKey, "Counters", NULL, &dwType,
(LPBYTE) pTitles, &cbMaxValueData))
{
MessageBox(hFrame, "RegQueryValueEx failed!", szAppName,
MB_ICONSTOP | MB_OK);
RegCloseKey(hKey);
return(FALSE);
}
// release the handle for the subkey
RegCloseKey(hKey);
return(TRUE);
}
//
// FindTitle() -- look up the object type index in the title database
// that was read by GetObjectTitles(). Return a pointer to the title
// string if a match is found, otherwise return a pointer to "Unknown".
//
PSTR FindTitle(INT TitleIndex)
{
INT i; // scratch object index
PSTR p = pTitles; // start of title database
while(*p)
{
i = atoi(p); // convert index string
p += strlen(p) + 1; // point to title string
if(i == TitleIndex) // is this desired index?
return(p); // yes, return addr of title
p += strlen(p) + 1; // no, go to next index
}
return("Unknown"); // no match was found
}
//
// FindGroup() -- Searches for the object group which has the
// specified title. Returns pointer to the beginning of the group's
// instance storage if match is found, otherwise a NULL pointer.
//
PPERFGROUP FindGroup(PSTR GroupName)
{
INT iCurGroup;
PPERFGROUP pCurGroup;
// point to the first group of objects
pCurGroup = pFirstGroup;
// compare title for each object type against supplied string
for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
{
// if titles match, return pointer to first instance
if(!strcmp((PSTR) pCurGroup->ObjectNameTitle, GroupName))
return(pCurGroup);
// advance to next group of objects
pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup +
pCurGroup->TotalByteLength);
}
return(NULL); // no match was found
}